/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.simple;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.MoveRequestMessage;
import cn.easyplatform.messages.vos.MoveResultVo;
import cn.easyplatform.messages.vos.MoveVo;
import cn.easyplatform.messages.vos.datalist.ListUpdatableRowVo;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.type.Constants;
import cn.easyplatform.type.FieldVo;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.ext.ComponentBuilder;
import cn.easyplatform.web.ext.zul.ListboxExt;
import cn.easyplatform.web.ext.zul.Movebox;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.MainTaskSupport;
import cn.easyplatform.web.task.event.EventListenerHandler;
import cn.easyplatform.web.task.zkex.list.OperableListSupport;
import org.apache.commons.lang3.ArrayUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.A;

import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class MoveboxBuilder implements ComponentBuilder, EventListener<Event> {

    private OperableHandler main;

    private Movebox mb;

    public MoveboxBuilder(OperableHandler mainTaskHandler, Movebox mb) {
        this.main = mainTaskHandler;
        this.mb = mb;
    }

    @Override
    public Component build() {
        if (Strings.isBlank(mb.getSource()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "source");
        if (Strings.isBlank(mb.getTarget()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "target");
        if (Strings.isBlank(mb.getFilter()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "filter");
        if (Strings.isBlank(mb.getMapping()))
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "mapping");
        String[] images = Strings.isBlank(mb.getImage()) ? null : mb.getImage()
                .split(",");
        if (images != null && images.length != 4)
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "image");
        String[] icons = Strings.isBlank(mb.getIconSclass()) ? null : mb
                .getIconSclass().split(",");
        if (icons != null && icons.length != 4)
            throw new EasyPlatformWithLabelKeyException(
                    "component.property.not.found", "<movebox>", "iconSclass");
        if (!mb.isDisabled() && main.getAccess() != null && !Strings.isBlank(mb.getAccess())) {
            String[] qx = mb.getAccess().split(",");
            boolean search = false;
            for (String power : qx) {
                if (ArrayUtils.contains(main.getAccess(), power)) {
                    search = true;
                    break;
                }
            }
            mb.setDisabled(!search);
        }
        List<String> display = null;
        if (!Strings.isBlank(mb.getDisplay())) {
            String[] vals = mb.getDisplay().split(",");
            display = Lang.array2list(vals);
        }
        if (display == null || display.contains("0")) {
            A a = new A();
            a.setAttribute("type", 0);
            a.setHflex("1");
            if (images != null)
                a.setImage(images[0]);
            else if (icons != null)
                a.setIconSclass(icons[0]);
            else
                a.setImage("~./images/rightrightarrow_g.png");
            a.addEventListener(Events.ON_CLICK, this);
            a.setDisabled(mb.isDisabled());
            a.setParent(mb);
        }
        if (display == null || display.contains("1")) {
            A a = new A();
            a.setAttribute("type", 1);
            if (images != null)
                a.setImage(images[1]);
            else if (icons != null)
                a.setIconSclass(icons[1]);
            else
                a.setImage("~./images/rightarrow_g.png");
            a.addEventListener(Events.ON_CLICK, this);
            a.setDisabled(mb.isDisabled());
            a.setParent(mb);
        }
        if (display == null || display.contains("2")) {
            A a = new A();
            a.setAttribute("type", 2);
            if (images != null)
                a.setImage(images[1]);
            else if (icons != null)
                a.setIconSclass(icons[1]);
            else
                a.setImage("~./images/leftarrow_g.png");
            a.addEventListener(Events.ON_CLICK, this);
            a.setDisabled(mb.isDisabled());
            a.setParent(mb);
        }
        if (display == null || display.contains("3")) {
            A a = new A();
            a.setAttribute("type", 3);
            if (images != null)
                a.setImage(images[1]);
            else if (icons != null)
                a.setIconSclass(icons[1]);
            else
                a.setImage("~./images/leftleftarrow_g.png");
            a.addEventListener(Events.ON_CLICK, this);
            a.setDisabled(mb.isDisabled());
            a.setParent(mb);
        }
        return mb;
    }

    @Override
    public void onEvent(Event evt) throws Exception {
        Object source = ((MainTaskSupport) main).getManagedEntityComponent(mb
                .getSource());
        if (source == null) {// 源表可以多样
            source = main.getManagedComponents().get(mb.getSource());
            if (source == null || !(source instanceof ListboxExt))
                throw new WrongValueException(evt.getTarget(), Labels.getLabel(
                        "move.btn.source.not.found",
                        new String[]{mb.getSource()}));
            if (!Strings.isBlank(((ListboxExt) source).getGroupField()))
                throw new WrongValueException(evt.getTarget(), Labels.getLabel(
                        "move.btn.source.invalid",
                        new String[]{mb.getSource()}));
        }
        Object target = (OperableListSupport) ((MainTaskSupport) main)
                .getManagedEntityComponent(mb.getTarget());
        if (target == null) {// 目标表也可以多样
            target = main.getManagedComponents().get(mb.getTarget());
            if (target == null || !(target instanceof ListboxExt))
                throw new WrongValueException(evt.getTarget(), Labels.getLabel(
                        "move.btn.target.not.found",
                        new String[]{mb.getTarget()}));
            if (!Strings.isBlank(((ListboxExt) target).getGroupField()))
                throw new WrongValueException(evt.getTarget(), Labels.getLabel(
                        "move.btn.target.invalid",
                        new String[]{mb.getSource()}));
        }
        int type = (Integer) evt.getTarget().getAttribute("type");
        move(evt.getTarget(), type, source, target);
    }

    @SuppressWarnings("unchecked")
    private void move(Component btn, int type, Object source, Object target)
            throws Exception {
        MoveVo mv = new MoveVo(type, mb.isUnique(), mb.getSource(),
                mb.getTarget(), mb.getFilter(), mb.getMapping());
        List<Object[]> sourceData = null;
        List<Object[]> targetData = null;
        if (type < 2) {
            if (source instanceof ListboxExt) {// 不管移左移右
                ListboxExt list = (ListboxExt) source;
                sourceData = list.getData(type == 1);// 只有单笔左移右才选部分选中的记录，否则选择所有
            } else {
                OperableListSupport os = (OperableListSupport) source;
                sourceData = os.getKeys(type == 1);
            }
            if (type == 1 && sourceData.isEmpty())// 左移到右不能为空
                throw new WrongValueException(btn,
                        Labels.getLabel("move.btn.not.select"));
            // 如果目标不是detail类型，必须送列表的记录集到后台
            if (target instanceof ListboxExt) {
                ListboxExt listbox = (ListboxExt) target;
                targetData = listbox.getData(false);
                mv.setListboxQuery(listbox.getQuery());
            } else {
                OperableListSupport os = (OperableListSupport) target;
                if (!os.getEntity().getType().equals(Constants.DETAIL))
                    targetData = os.getKeys(false);
            }
        } else {
            if (target instanceof ListboxExt) {
                ListboxExt list = (ListboxExt) target;
                targetData = list.getData(type == 2);
            } else {
                OperableListSupport os = (OperableListSupport) target;
                targetData = os.getKeys(type == 2);
            }
            if (type == 2 && targetData.isEmpty())// 右移到左
                throw new WrongValueException(btn,
                        Labels.getLabel("move.btn.not.select"));
            if (source instanceof ListboxExt) {
                ListboxExt listbox = (ListboxExt) source;
                sourceData = listbox.getData(false);
                mv.setListboxQuery(listbox.getQuery());
            } else {
                OperableListSupport os = (OperableListSupport) source;
                // 如果源不是detail类型，必须送列表的记录集到后台
                if (!os.getEntity().getType().equals(Constants.DETAIL))
                    sourceData = os.getKeys(false);
            }
        }
        ComponentService cs = ServiceLocator
                .lookup(ComponentService.class);
        mv.setTargetData(targetData);
        mv.setSourceData(sourceData);
        IResponseMessage<?> resp = cs.move(new MoveRequestMessage(main.getId(),
                mv));
        if (!resp.isSuccess())
            throw new WrongValueException(btn, (String) resp.getBody());
        List<MoveResultVo> list = (List<MoveResultVo>) resp.getBody();
        if (type < 2) {
            for (MoveResultVo mrv : list) {
                if (mrv.getData() instanceof ListRowVo) {// 列表
                    ListRowVo rv = (ListRowVo) mrv.getData();
                    OperableListSupport os = (OperableListSupport) target;
                    os.update(new ListUpdatableRowVo(rv.getKeys(), rv
                            .getData(), mrv.getIndex() < 0, false));
                    os.refreshFoot();
                } else {
                    if (mrv.getIndex() < 0) {
                        List<FieldVo[]> data = new ArrayList<FieldVo[]>(1);
                        data.add((FieldVo[]) mrv.getData());
                        ((ListboxBuilder) ((ListboxExt) target)
                                .getAttribute("$proxy")).redraw(data);
                    } else
                        ((ListboxExt) target).update((FieldVo[]) mrv.getData(),
                                mrv.getIndex());
                }
                if (mb.isUnique()) {// 不能重复
                    if (source instanceof OperableListSupport) {
                        OperableListSupport os = (OperableListSupport) source;
                        os.doItem(
                                mrv.getOrginData(), mrv.isDropSource() ? 0 : 1);
                        os.refreshFoot();
                    } else
                        ((ListboxExt) source).remove(mrv.getOrginData());
                }
            }
        } else {
            for (MoveResultVo mrv : list) {
                if (mrv.getData() instanceof ListRowVo) {// 列表
                    ListRowVo rv = (ListRowVo) mrv.getData();
                    OperableListSupport os = ((OperableListSupport) source);
                    os.update(new ListUpdatableRowVo(rv.getKeys(), rv
                            .getData(), mrv.getIndex() < 0, false));
                    os.refreshFoot();
                } else {// listbox
                    if (mrv.getIndex() < 0) {
                        List<FieldVo[]> data = new ArrayList<FieldVo[]>(1);
                        data.add((FieldVo[]) mrv.getData());
                        ((ListboxBuilder) ((ListboxExt) target)
                                .getAttribute("$proxy")).redraw(data);
                    } else
                        ((ListboxExt) source).update((FieldVo[]) mrv.getData(),
                                mrv.getIndex());
                }
                if (mb.isUnique()) {// 不能重复
                    if (target instanceof OperableListSupport) {
                        OperableListSupport os = (OperableListSupport) target;
                        os.doItem(
                                mrv.getOrginData(), mrv.isDropSource() ? 0 : 1);
                        os.refreshFoot();
                    } else
                        ((ListboxExt) target).remove(mrv.getOrginData());
                }
            }
        }
        if (!Strings.isBlank(mb.getEvent())) {
            EventListenerHandler elh = new EventListenerHandler(Events.ON_CLICK, main,
                    mb.getEvent());
            elh.onEvent(new Event(Events.ON_CLICK, btn, type));
        }
    }

}
